package cn.itcast.zt.demo01;

import com.lmax.disruptor.EventTranslatorOneArg;
import com.lmax.disruptor.RingBuffer;

import java.nio.ByteBuffer;

/**
 * 和StringEventProducer类功能一样，disruptor3推荐的写法，这样更灵活
 * 一个Translator可以看做一个事件初始化器
 * create by zhangtian3 on 2018/10/9
 */
public class StringEventProducerWithTranslator {
    private final RingBuffer<StringEvent> ringBuffer;

    public StringEventProducerWithTranslator( RingBuffer<StringEvent> ringBuffer) {
        this.ringBuffer = ringBuffer;
    }

    /**
     * 很明显的是：当用一个简单队列来发布事件的时候会牵涉更多的细节，这是因为事件对象还需要预先创建。
     * 发布事件最少需要两步：获取下一个事件槽并发布事件（发布事件的时候要使用try/finnally保证事件一定会被发布）。
     * 如果我们使用RingBuffer.next()获取一个事件槽，那么一定要发布对应的事件。
     * 如果不能发布事件，那么就会引起Disruptor状态的混乱。
     * 尤其是在多个事件生产者的情况下会导致事件消费者失速，从而不得不重启应用才能会恢复。
     */
    // 填充数据
    public static final EventTranslatorOneArg<StringEvent, ByteBuffer> TRANSLATOR = new EventTranslatorOneArg<StringEvent, ByteBuffer>() {
        @Override
        public void translateTo(StringEvent stringEvent, long sequence, ByteBuffer byteBuffer) {
            // 从byteBuffer中读取传过来的值
            byteBuffer.flip();
            byte[] dst = new byte[byteBuffer.limit()];
            byteBuffer.get(dst, 0, dst.length);
            byteBuffer.clear();
            // 为stringEvent赋值，填充数据
            stringEvent.setValue(new String(dst));
            stringEvent.setId((int) sequence);
        }
    };

    // 发布事件
    public void sendData(ByteBuffer byteBuffer) {
        ringBuffer.publishEvent(TRANSLATOR, byteBuffer);
    }
}
